home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / cmdlg7.zip / PRN31_.PAS < prev    next >
Pascal/Delphi Source File  |  1992-12-10  |  17KB  |  787 lines

  1. {$IFDEF WINDOWS}
  2.  
  3. {µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ}
  4. {   \\\                                    }
  5. {  -(j)-                                   }
  6. {    /juanca                               }
  7. {    ~                                     }
  8. {   ⌐ ACASA 1989-1992, All rights reserved }
  9. {µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ}
  10.  
  11. {a tPrinter object, that knows about tUsrWin windows, and how to tell them to print }
  12. { also uses CommonDlgs for Print, and PrinterSetup }
  13.  
  14. {$ENDIF}
  15. UNIT PRN31_;
  16. {$C MOVEABLE DEMANDLOAD DISCARDABLE}
  17. INTERFACE
  18.    USES
  19.      WINTYPES,
  20.      WIN31,
  21.      OBJECTS,
  22.      OWINDOWS,
  23.      ODIALOGS,
  24.      COMMDLG,
  25.      PORT_,
  26.      USRWIN_,
  27.      PRINTDLG;
  28.  
  29.    { TPrintout banding flags }
  30.    CONST
  31.      pf_Graphics  = $01;        { Current band only accepts text }
  32.      pf_Text      = $02;        { Current band only accepts graphics }
  33.      pf_Both      = $03;        { Current band accepts both text and
  34.                                graphics }
  35.    TYPE
  36.       pAbortProc = ^TAbortProc;
  37.  
  38.       tBandInfoStruct = RECORD
  39.         fGraphicsFlag: Bool;
  40.         fTextFlag: Bool;
  41.         GraphcisRect: TRect;
  42.       END;
  43.  
  44.  
  45.   TYPE
  46.     PAbortPrintDlg = ^TAbortPrintDlg;
  47.     TAbortPrintDlg = OBJECT (tDlgWindow)
  48.       CONSTRUCTOR
  49.         init(iparent:PWindowsObject; name :pChar; msg:pChar);
  50.  
  51.       DESTRUCTOR
  52.         done;
  53.           virtual;
  54.       PROCEDURE
  55.         setupWindow;
  56.           virtual;
  57.       PROCEDURE
  58.         wmCommand(var msg:TMessage);
  59.           virtual
  60.             wm_First+wm_Command;
  61.  
  62.       PROCEDURE
  63.       destroy;
  64.         virtual;
  65.  
  66.       PROCEDURE
  67.       wmDestroy(var msg :tMessage);
  68.         virtual
  69.           wm_First+wm_Destroy;
  70.     PRIVATE
  71.       _msg :array[0..200] of Char;
  72.     END;
  73.  
  74.  
  75.    TYPE
  76.      Super      = TPort;
  77.      PPrinter = ^TPrinter;
  78.      TPrinter = OBJECT (Super)
  79.  
  80.        printerData :tPrintDlg;
  81.  
  82.  
  83.        CONSTRUCTOR
  84.          init;
  85.        DESTRUCTOR
  86.          done;
  87.            virtual;
  88.  
  89.        FUNCTION
  90.          context:THandle;
  91.            virtual;
  92.  
  93.        FUNCTION
  94.        isPrinter :Boolean;
  95.          virtual;
  96.  
  97.        FUNCTION
  98.        cycle:Boolean;
  99.          virtual;
  100.  
  101.        FUNCTION
  102.        printFlags :Longint;
  103.          virtual;
  104.  
  105.        FUNCTION
  106.        setupTemplate :pChar;
  107.          virtual;
  108.  
  109.        FUNCTION
  110.        optionsTemplate :pChar;
  111.          virtual;
  112.  
  113.        FUNCTION
  114.        abortTemplate :pChar;
  115.          virtual;
  116.  
  117.        FUNCTION
  118.        makeOptionsDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintOptDlg;
  119.          virtual;
  120.  
  121.        FUNCTION
  122.        makeSetupDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintSetupDlg;
  123.          virtual;
  124.  
  125.        FUNCTION
  126.        makeAbortDlg(wnd :pWindowsObject; msg :pChar) :pAbortPrintDlg;
  127.          virtual;
  128.  
  129.        PROCEDURE
  130.        getDevNames(devNames :pDevNames; var driver, device, output :pChar);
  131.  
  132.        FUNCTION
  133.          errors:Boolean;
  134.        FUNCTION
  135.          aborted:Boolean;
  136.        FUNCTION
  137.          errorNo:Integer;
  138.  
  139.        FUNCTION
  140.        calcBandingFlags(var band :tRect; firstBand :Boolean) :Word;
  141.  
  142.  
  143.        FUNCTION
  144.        print(awin: pUsrWin; docName :pChar): Boolean;
  145.          virtual;
  146.  
  147.        PROCEDURE
  148.          startDoc(win:PWindowsObject; docName:pChar);
  149.        PROCEDURE
  150.          endDoc;
  151.        PROCEDURE
  152.          abortDoc;
  153.  
  154.        FUNCTION
  155.          nextBand(var box:tRect) :Boolean;
  156.  
  157.        PROCEDURE
  158.          startPage;
  159.        PROCEDURE
  160.          endPage;
  161.  
  162.        PROCEDURE
  163.          setAbortProc(proc :tAbortProc);
  164.  
  165.        PROCEDURE
  166.          getPageSize(var dim:tPoint);
  167.  
  168.        PROCEDURE
  169.          printingOffset(var off :tPoint);
  170.  
  171.  
  172.        FUNCTION
  173.        banding :Boolean;
  174.  
  175.        FUNCTION
  176.        options(wnd :pUsrWin):Boolean;
  177.  
  178.        PROCEDURE
  179.        setup(wnd :pWindowsObject);
  180.  
  181.      PRIVATE
  182.        _errorNo     :Integer;
  183.        _abortProc   :tFarProc;
  184.        _banding,
  185.        _useBandInfo :Boolean;
  186.      END;{OBJECT TDevice}
  187.  
  188.  
  189.  
  190. IMPLEMENTATION
  191.   USES
  192.     WINPROCS,
  193.     STRINGS;
  194.  
  195.   CONST
  196.     userAbort    :Boolean = TRUE;
  197.     printErrors  :Boolean = FALSE;
  198.     abortDlg     :pWindowsObject = nil;
  199.     id_Msg                = 100;
  200.  
  201.  
  202.   FUNCTION
  203.   {}
  204.   printingAbort(hdc :THandle; code :Integer) :Boolean;
  205.   export;
  206.       var
  207.         msg :TMsg;
  208.       begin
  209.         printErrors := printErrors or (code <> 0);
  210.         while not (userAbort or printErrors)
  211.         and peekMessage(msg, 0, 0, 0, pm_Remove)
  212.         do
  213.           if not application^.processAppMsg(msg)
  214.           then begin
  215.             TranslateMessage(Msg);
  216.             DispatchMessage(Msg);
  217.           end;
  218.         printingAbort := not (userAbort or printErrors)
  219.       end;
  220.  
  221.    CONSTRUCTOR
  222.    TAbortPrintDlg.
  223.      {}
  224.    init(iparent:PWindowsObject; name :pChar; msg:pChar);
  225.      begin
  226.        inherited init(iparent, name);
  227.        strCopy(_msg, msg);
  228.      end;
  229.  
  230.  
  231.    PROCEDURE
  232.    TAbortPrintDlg.
  233.      {}
  234.    setupWindow;
  235.      begin
  236.        abortDlg := @self;
  237.        inherited setupWindow;
  238.        setDlgItemText(hwindow, id_Msg, _msg);
  239.  
  240.        enableWindow(application^.mainWindow^.hwindow, FALSE);
  241.        show(sw_Normal);
  242.        setFocus(hwindow);
  243.        updateWindow(hwindow);
  244.      end;
  245.  
  246.    DESTRUCTOR
  247.    TAbortPrintDlg.
  248.      {}
  249.    done;
  250.      begin
  251.        abortDlg := nil;
  252.        inherited done
  253.      end;
  254.  
  255.  
  256.    PROCEDURE
  257.    TAbortPrintDlg.
  258.      {}
  259.    wmCommand(var msg:TMessage);
  260.      begin
  261.        inherited wmCommand(msg);
  262.        userAbort    := TRUE;
  263.      end;
  264.  
  265.  
  266.    PROCEDURE
  267.    TAbortPrintDlg.
  268.      {}
  269.    destroy;
  270.      begin
  271.        with application^.mainWindow^
  272.        do begin
  273.          enableWindow(hwindow, TRUE);
  274.          setFocus(hwindow);
  275.        end;
  276.        inherited destroy;
  277.      end;
  278.  
  279.  
  280.    PROCEDURE
  281.    TAbortPrintDlg.
  282.      {}
  283.    wmDestroy(var msg :tMessage);
  284.      begin
  285.        with application^.mainWindow^
  286.        do begin
  287.          enableWindow(hwindow, TRUE);
  288.          setFocus(hwindow);
  289.        end;
  290.        inherited wmDestroy(msg)
  291.      end;
  292.  
  293.  
  294.    CONSTRUCTOR
  295.    TPrinter.
  296.      {}
  297.    init;
  298.      var
  299.        esc :Integer;
  300.      begin
  301.        if not Super.init
  302.        then
  303.          fail;
  304.        _errorNo   := 1;
  305.        _abortProc := nil;
  306.        userAbort   := FALSE;
  307.        fillChar(printerData, sizeOf(printerData), 0);
  308.        with printerData
  309.        do begin
  310.          lStructSize   := sizeof(printerData);
  311.          hInstance     := SYSTEM.HInstance;
  312.          flags         := pd_ReturnDC or pd_ReturnDefault;
  313.          nMinPage      := 0;
  314.          nMaxPage      := 0;
  315.        end;
  316.  
  317.        if not COMMDLG.printDlg(printerData)
  318.        then
  319.          fail;
  320.  
  321.        printerData.flags := printFlags;
  322.  
  323.  
  324.        setAbortProc(printingAbort);
  325.        _banding := (getDeviceCaps(context, RasterCaps) and rc_Banding) <> 0;
  326.        esc := WINTYPES.BANDINFO;
  327.        _useBandInfo := escape(context, queryEscSupport, sizeOf(esc), @esc, nil) <> 0;
  328.      end;
  329.  
  330.    DESTRUCTOR
  331.    TPrinter.
  332.      {}
  333.    done;
  334.      begin
  335.        if abortDlg <> nil
  336.        then begin
  337.           dispose(abortDlg, done);
  338.           abortDlg := nil
  339.        end;
  340.        with printerData
  341.        do begin
  342.          deleteDC(context);
  343.          globalFree(hDevMode);
  344.          globalFree(hDevNames)
  345.        end;
  346.        Super.done
  347.      end;
  348.  
  349.    FUNCTION
  350.    TPrinter.
  351.      {}
  352.    context:THandle;
  353.      begin
  354.        context := printerData.hDC
  355.      end;
  356.  
  357.    FUNCTION
  358.    tPrinter.
  359.    {}
  360.    printFlags :Longint;
  361.      begin
  362.        printFlags :=    pd_ReturnDC or
  363.                         pd_UseDevModeCopies or
  364.                         pd_NoSelection or
  365.                         pd_NoPageNums or
  366.                         pd_NoWarning
  367.      end;
  368.  
  369.    PROCEDURE
  370.    TPrinter.
  371.      {}
  372.    getDevNames(devNames :pDevNames; var driver, device, output :pChar);
  373.      var
  374.        str :pChar absolute devNames;
  375.      begin
  376.        with devNames^
  377.        do begin
  378.          driver := str+wDriverOffset;
  379.          device := str+wDeviceOffset;
  380.          output := str+wOutputOffset;
  381.        end
  382.      end;
  383.  
  384.    FUNCTION
  385.    TPrinter.
  386.      {}
  387.    errors:Boolean;
  388.      begin
  389.        errors := (_errorNo <= 0) or printErrors
  390.      end;
  391.  
  392.    FUNCTION
  393.    TPrinter.
  394.      {}
  395.    aborted:Boolean;
  396.      begin
  397.        aborted := userAbort
  398.      end;
  399.  
  400.    FUNCTION
  401.    TPrinter.
  402.      {}
  403.    errorNo :Integer;
  404.      begin
  405.        errorNo := _errorNo
  406.      end;
  407.  
  408.    PROCEDURE
  409.    TPrinter.
  410.      {}
  411.    startDoc(win:PWindowsObject; docName:pChar);
  412.      var
  413.        winDC  :PPort;
  414.        abdlg  :PAbortPrintDlg;
  415.        msg    :array[0..300] of Char;
  416.        devName,
  417.        driver,
  418.        outp   :pChar;
  419.  
  420.        info   :TDocInfo;
  421.  
  422.      begin
  423.        with printerData
  424.        do begin
  425.          getDevNames(globalLock(hDevNames), driver, devName, outp);
  426.          globalUnlock(hDevNames)
  427.        end;
  428.        strPCopy(msg, 'Printing'#10+
  429.                      strPas(docName)+#10+
  430.                      'on'#10+
  431.                      strPas(devName)+#10+
  432.                      'connected to'+#10+
  433.                      strPas(outp)
  434.                      );
  435.        if not errors
  436.        then begin
  437.          abortDlg := application^.makeWindow(makeAbortDlg(win, msg));
  438.          if abortDlg = nil
  439.          then
  440.            exit
  441.        end;
  442.        userAbort   := FALSE;
  443.        printErrors := FALSE;
  444.  
  445.        with info
  446.        do begin
  447.          cbSize := sizeOf(info);
  448.          lpszDocName := docName;
  449.          lpszOutput   := nil
  450.        end;
  451.        _errorNo := WIN31.setAbortProc(context, tAbortProc(_abortProc));
  452.        if not errors
  453.        then
  454.          _errorNo := WIN31.startDoc(context, info)
  455.      end;
  456.  
  457.    PROCEDURE
  458.    TPrinter.
  459.      {}
  460.    endDoc;
  461.      begin
  462.        if not errors
  463.        and not aborted
  464.        then
  465.          _errorNo := WIN31.endDoc(context)
  466.        else
  467.          abortDoc;
  468.        if abortDlg <> nil
  469.        then begin
  470.           dispose(abortDlg, done);
  471.           abortDlg := nil
  472.        end
  473.      end;
  474.  
  475.    PROCEDURE
  476.    TPrinter.
  477.      {}
  478.    abortDoc;
  479.      begin
  480.        userAbort := TRUE;
  481.        _errorNo := WIN31.abortDoc(context);
  482.        if abortDlg <> nil
  483.        then begin
  484.           dispose(abortDlg, done);
  485.           abortDlg := nil
  486.        end;
  487.      end;
  488.  
  489.    FUNCTION
  490.    TPrinter.
  491.      {}
  492.    nextBand(var box:tRect) :Boolean;
  493.      begin
  494.        if banding then
  495.          _errorNo := escape(context, WinTypes.NEXTBAND, 0, nil, @box)
  496.        else
  497.          _errorNo := escape(context, WinTypes.GetPhysPageSize, 0, nil, @box);
  498.        nextBand := not isRectEmpty(box) and not errors and not userAbort
  499.      end;
  500.  
  501.    PROCEDURE
  502.    TPrinter.
  503.      {}
  504.    getPageSize(var dim:tPoint);
  505.      begin
  506.        _errorNo := escape(context, WinTypes.GetPhysPageSize, 0, nil, @dim);
  507.      end;
  508.  
  509.    PROCEDURE
  510.    TPrinter.
  511.      {}
  512.    printingOffset(var off :tPoint);
  513.      begin
  514.        _errorNo := escape(context, WinTypes.GetPrintingOffset, 0, nil, @off);
  515.      end;
  516.  
  517.  
  518.    PROCEDURE
  519.    TPrinter.
  520.      {}
  521.    startPage;
  522.      begin
  523.        _errorNo := WIN31.startPage(context)
  524.      end;
  525.  
  526.    PROCEDURE
  527.    TPrinter.
  528.      {}
  529.    endPage;
  530.      begin
  531.        {_errorNo := }WIN31.endPage(context)
  532.      end;
  533.  
  534.    PROCEDURE
  535.    TPrinter.
  536.      {}
  537.    setAbortProc(proc :tAbortProc);
  538.      begin
  539.        _abortProc := makeProcInstance(@proc, hinstance);
  540.        WIN31.setAbortProc(context, tAbortProc(_abortProc))
  541.      end;
  542.  
  543.    FUNCTION
  544.    tPrinter.
  545.    {}
  546.    isPrinter :Boolean;
  547.      begin
  548.        isPrinter := TRUE
  549.      end;
  550.  
  551.    FUNCTION
  552.    TPrinter.
  553.      {}
  554.    cycle:Boolean;
  555.      begin
  556.          cycle := tAbortProc(_abortProc)(context, 0) and not errors;
  557.      end;
  558.  
  559.    FUNCTION
  560.    TPrinter.
  561.      {}
  562.    banding :Boolean;
  563.      begin
  564.        banding := _banding
  565.      end;
  566.  
  567.    FUNCTION
  568.    tPrinter.
  569.    {}
  570.    setupTemplate :pChar;
  571.      begin
  572.        setupTemplate := nil
  573.      end;
  574.  
  575.    FUNCTION
  576.    tPrinter.
  577.    {}
  578.    optionsTemplate :pChar;
  579.      begin
  580.        optionsTemplate := nil
  581.      end;
  582.  
  583.    FUNCTION
  584.    tPrinter.
  585.    {}
  586.    abortTemplate :pChar;
  587.      begin
  588.        abortTemplate := 'PRINTING_DLG'
  589.      end;
  590.  
  591.    FUNCTION
  592.    tPrinter.
  593.    {}
  594.    makeOptionsDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintOptDlg;
  595.      begin
  596.       makeOptionsDlg :=  new( pPrintOptDlg, init(wnd, optionsTemplate, data, makeSetupDlg(wnd, data)));
  597.      end;
  598.  
  599.    FUNCTION
  600.    tPrinter.
  601.    {}
  602.    makeSetupDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintSetupDlg;
  603.      begin
  604.       makeSetupDlg :=  new( pPrintSetupDlg,init(wnd, setupTemplate, @printerData));
  605.      end;
  606.  
  607.    FUNCTION
  608.    tPrinter.
  609.    {}
  610.    makeAbortDlg(wnd :pWindowsObject; msg :pChar) :pAbortPrintDlg;
  611.      begin
  612.       makeAbortDlg :=  new( pAbortPrintDlg,init(wnd, abortTemplate, msg));
  613.      end;
  614.  
  615.    FUNCTION
  616.    TPrinter.
  617.      {}
  618.    options(wnd :pUsrWin):Boolean;
  619.      begin
  620.        with printerData
  621.        do begin
  622.          wnd^.getPrintRange(nMinPage, nMaxPage);
  623.          flags := flags or wnd^.printFlags;
  624.          if nMinPage <> nMaxPage
  625.          then
  626.            flags := flags and not pd_NoPageNums
  627.        end;
  628.        options := id_Ok =
  629.        application^.execDialog(makeOptionsDlg(wnd, @printerData))
  630.      end;
  631.  
  632.  
  633.    PROCEDURE
  634.    TPrinter.
  635.      {}
  636.    setup(wnd :pWindowsObject);
  637.      begin
  638.        with printerData
  639.        do
  640.          flags := flags or printFlags;
  641.        application^.execDialog(makeSetupDlg(wnd, @printerData))
  642.      end;
  643.  
  644.    FUNCTION
  645.    tPrinter.
  646.    {}
  647.    calcBandingFlags(var band :tRect; firstBand :Boolean) :Word;
  648.      var
  649.        BandInfoRec  :TBandInfoStruct;
  650.        pFlags       :Word;
  651.        flags        :Word;
  652.        pageSize     :tPoint;
  653.      begin
  654.        { Calculate text verses graphics banding }
  655.        if _useBandInfo
  656.        then begin
  657.          escape(context, bandInfo, sizeOf(tBandInfoStruct), nil, @BandInfoRec);
  658.          if bandInfoRec.fGraphicsFlag
  659.          then
  660.            pFlags := pf_Graphics;
  661.      (*    if BandInfoRec.fTextFlag then pFlags := pf_Text; *)
  662.          if BandInfoRec.fTextFlag
  663.          then pFlags := pFlags or pf_Text;
  664.          flags := (flags and not pf_Both) or pFlags;
  665.        end
  666.        else begin
  667.          { If a driver does not support BandInfo the Microsoft
  668.            Recommended way of determining text only bands is if
  669.            the first band is the full page, all others are
  670.            graphcis only.  Otherwise it handles both. }
  671.          getPageSize(pageSize);
  672.          if firstBand
  673.   {           and (LongInt((@band.left)^) = 0)  %% dunno what this is for}
  674.          and (band.right = PageSize.X)
  675.          and (band.bottom = PageSize.Y)
  676.          then
  677.            flags := pf_Text
  678.          else if Flags
  679.          and pf_Both = pf_Text
  680.          then
  681.            { All other bands are graphics only }
  682.            flags := (Flags and not pf_Both) or pf_Graphics
  683.          else
  684.            flags := flags or pf_Both;
  685.        end;
  686.  
  687.        calcBandingFlags := flags
  688.      end;
  689.  
  690.    FUNCTION
  691.    TPrinter.
  692.    {}
  693.    print(awin: pUsrWin; docName :pChar): Boolean;
  694.      var
  695.        PageSize      :tPoint;
  696.        band          :tRect;
  697.        firstBand     :Boolean;
  698.        flags         :Word;
  699.        pageNumber    :Word;
  700.  
  701.      begin
  702.         if not options(aWin)
  703.         then begin
  704.           print := TRUE;
  705.           exit
  706.         end;
  707.  
  708.         print := False; { Assume error occured }
  709.  
  710.        _errorNo := 0;
  711.  
  712.        if aWin = nil
  713.        then
  714.          exit;
  715.  
  716.        if context = 0
  717.        then
  718.          exit;
  719.  
  720.        { Get the page size }
  721.        getPageSize(pageSize);
  722.  
  723.        if not banding
  724.        then
  725.          with pageSize
  726.          do
  727.            setRect(band, 0, 0, x, y)
  728.        else begin
  729.          { Only use BandInfo if supported (note: using Flags as a temporary) }
  730.          flags := bandInfo;
  731.        end;
  732.  
  733.        flags := pf_Both;
  734.  
  735.        startDoc(aWin, docName);
  736.  
  737.        pageNumber := printerData.nMinPage;
  738.        if not errors
  739.        then begin
  740.          repeat
  741.            startPage;
  742.            if banding
  743.            then begin
  744.              firstBand := TRUE;
  745.              nextBand(band)
  746.            end;
  747.            repeat
  748.              { Call the abort proc between bands or pages }
  749.              cycle;
  750.  
  751.              if banding
  752.              then begin
  753.                flags := calcBandingFlags(band, firstBand);
  754.                if {(Printout^.ForceAllBands)} FALSE and (Flags and pf_Both = pf_Text)
  755.                then
  756.                  setPixel(0, 0, 0);
  757.              end;
  758.  
  759.              if not errors
  760.              then
  761.                aWin^.printPage(@self, pageNumber, pageSize, band, flags);
  762.              firstBand := FALSE
  763.            until
  764.               errors or
  765.               not banding
  766.               or not nextBand(band);
  767.  
  768.            { NewFrame should only be called if not banding }
  769.            if not errors
  770.            then
  771.              endPage;
  772.  
  773.            inc(pageNumber);
  774.          until
  775.            errors    or
  776.            userAbort or
  777.            (pageNumber > printerData.nMaxPage);
  778.  
  779.          { Tell GDI the document is finished }
  780.          endDoc
  781.        end;
  782.  
  783.        print := not errors
  784.      end;
  785.  
  786.  
  787. END.